home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 2000 November: Tool Chest / Dev.CD Nov 00 TC Disk 1.toast / Sample Code / Archive / Networking / TCP Server / network.c < prev    next >
Encoding:
C/C++ Source or Header  |  2000-09-28  |  5.9 KB  |  240 lines  |  [TEXT/KAHL]

  1. /*
  2.     TCP Client/Server Queuing Example
  3.     Steve Falkenburg, MacDTS, Apple Computer
  4.     3/11/92
  5.     
  6.     this client/server sample uses MacTCP to implement a simple "greeting" server.  the server
  7.     opens up several listeners on kGreetingPort (1235).  when a client connects, the data entered
  8.     in the greeting dialog is sent to the remote connection, and the connection is closed.
  9.     
  10.     connection management is done through the use of Operating System queues to simplify tracking
  11.     and usage.
  12. */
  13.  
  14.  
  15. #include <Processes.h>
  16. #include <MacTCPCommonTypes.h>
  17. #include <TCPPB.h>
  18.  
  19. #include "const.h"
  20. #include "globals.h"
  21. #include "utils.h"
  22. #include "queues.h"
  23. #include "network.h"
  24.  
  25. void StartListener(TCPiopb *pBlock);
  26. void ListenerCompletion(MyQElemPtr iopb);
  27. void SendData(TCPiopb *pBlock,StringPtr data);
  28.  
  29.  
  30. /*    initialize TCP/IP driver and create our queues, putting them on the unused list
  31. */
  32.  
  33. OSErr InitNetwork(void)
  34. {
  35.     OSErr err;
  36.     TCPiopb *pBlock;
  37.     short i;
  38.     
  39.     err = OpenDriver("\p.ipp",&gTcpDrvrRef);
  40.     if (err!=noErr)
  41.         return err;
  42.     
  43.     for (i=0; i<kNumConnections; i++) {
  44.         pBlock = (TCPiopb *)GetUnusedPBlock();
  45.         if (pBlock)
  46.             StartListener(pBlock);
  47.     }
  48.     
  49.     return noErr;
  50. }
  51.  
  52.  
  53. /*    creates a connection end and assigns it to listen for an incoming connection on our
  54.     network port.
  55. */
  56.  
  57. void StartListener(TCPiopb *pBlock)
  58. {
  59.     Ptr rcvBuff;
  60.     OSErr err;
  61.         
  62.     rcvBuff = NewPtr(kRcvBuffSize);
  63.     if (MemError()!=noErr)
  64.         DoError(MemError());
  65.     
  66.     /* create a network stream */
  67.     
  68.     pBlock->csCode = TCPCreate;
  69.     pBlock->ioCRefNum = gTcpDrvrRef;
  70.     pBlock->csParam.create.rcvBuff = rcvBuff;
  71.     pBlock->csParam.create.rcvBuffLen = kRcvBuffSize;
  72.     pBlock->csParam.create.notifyProc = nil;
  73.     err = PBControl(pBlock,false);
  74.     if (err!=noErr)
  75.         DoError(err);
  76.     
  77.     /* create a listener */
  78.     
  79.     pBlock->csCode = TCPPassiveOpen;
  80. #ifdef __SYSEQU__
  81.     ((MyQElemPtr)pBlock)->savedA5 = *(long *)CurrentA5;
  82. #else    
  83.     ((MyQElemPtr)pBlock)->savedA5 = (long)CurrentA5;
  84. #endif
  85.     pBlock->ioCompletion = (ProcPtr)ListenerCompletion;
  86.     pBlock->csParam.open.ulpTimeoutValue = 0;
  87.     pBlock->csParam.open.ulpTimeoutAction = 1;
  88.     pBlock->csParam.open.validityFlags = 0xC0;
  89.     pBlock->csParam.open.commandTimeoutValue = 0;
  90.     pBlock->csParam.open.remoteHost = 0;
  91.     pBlock->csParam.open.remotePort = 0;
  92.     pBlock->csParam.open.localHost = 0;
  93.     pBlock->csParam.open.localPort = kGreetingPort;
  94.     pBlock->csParam.open.tosFlags = 0;
  95.     pBlock->csParam.open.precedence = 0;
  96.     pBlock->csParam.open.dontFrag = 0;
  97.     pBlock->csParam.open.timeToLive = 0;
  98.     pBlock->csParam.open.security = 0;
  99.     pBlock->csParam.open.optionCnt = 0;
  100.     PBControl(pBlock,true);
  101.  
  102.     gRunning++; // increment count of running parameter blocks
  103. }
  104.  
  105.  
  106. /*    called to release all network resources in response to a quit
  107. */
  108.  
  109. void CloseNetwork(void)
  110. {
  111.     THz theZone;
  112.     short drvrRefNum;
  113.     OSErr err;
  114.     TCPiopb tcpBlock;
  115.     StreamPtr *curStream;
  116.     long theStream;
  117.  
  118.     theZone = ApplicZone();
  119.     
  120.     tcpBlock.ioCRefNum = gTcpDrvrRef;
  121.     tcpBlock.csCode = TCPGlobalInfo;
  122.     err = PBControl((ParmBlkPtr)&tcpBlock,false);
  123.     if (err!=noErr)
  124.         return;
  125.     
  126.     curStream = *tcpBlock.csParam.globalInfo.tcpCDBTable;
  127.     while (*curStream) {
  128.     
  129.         theStream = *curStream;
  130.         
  131.         if (PtrZone((Ptr)theStream)==theZone) {                // only release streams in our heap 
  132.  
  133.             tcpBlock.csCode = TCPStatus;
  134.             tcpBlock.tcpStream = theStream;
  135.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  136.  
  137.             // abort connection 
  138.             
  139.             tcpBlock.csCode = TCPAbort;
  140.             tcpBlock.tcpStream = theStream;
  141.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  142.             
  143.             // release stream
  144.             
  145.             tcpBlock.csCode = TCPRelease;
  146.             tcpBlock.tcpStream = theStream;
  147.             err = PBControl((ParmBlkPtr)&tcpBlock,false);
  148.         }
  149.         
  150.         curStream++;
  151.     }
  152. }
  153.  
  154.  
  155. /*    this completion routine will be called when one of the listeners gets a connection from a
  156.     remote machine.  since we're using OS queues dispatched from the main event loop, we just
  157.     take the parameter block and put it on the completed queue.  if running seven, we call
  158.     WakeUpProcess() to return control to the application
  159. */
  160.  
  161. void ListenerCompletion(MyQElemPtr iopb)
  162. {
  163.     long saveA5;
  164.     ProcessSerialNumber currentProc;
  165.     
  166.     saveA5 = SetA5(iopb->savedA5);
  167.     
  168.     StoreCompletedPBlock(iopb);
  169.     gRunning--;
  170.     
  171.     if (gRunningSeven) {
  172.         WakeUpProcess(&gOurPSN);
  173.     }
  174.     
  175.     SetA5(saveA5);
  176. }
  177.  
  178.  
  179. /*    this routine is called from the event dispatcher of the event loop to continue processing
  180.     of completed listens received at interrupt time from ListenerCompletion.  We send them
  181.     some data, close the connection, and restart the listener, putting it back on MacTCP's queue
  182. */
  183.  
  184. void ProcessConnection(MyQElemPtr iopb)
  185. {
  186.     SendData(&iopb->tcpBlock,gGreetingData);
  187.     RecycleFreePBlock(iopb);
  188.     iopb = GetUnusedPBlock();
  189.     if (iopb)
  190.         StartListener(&iopb->tcpBlock);
  191. }
  192.  
  193.  
  194. /*    here, we send some data to the remote host over the opened connection and close the connection
  195.     when done.  if we didn't use os queues, this code would be much more complicated, since it
  196.     would have to be interrupt safe, and we would have to perform all driver calls async with
  197.     linked completion routines (yuck)
  198. */
  199.  
  200. void SendData(TCPiopb *pBlock,StringPtr data)
  201. {
  202.     OSErr err;
  203.     wdsEntry wdsPtr[4];
  204.     char crlf[] = "\015\012";
  205.  
  206.     wdsPtr[0].length = wdsPtr[2].length = 2;
  207.     wdsPtr[0].ptr = wdsPtr[2].ptr = crlf;
  208.     wdsPtr[1].length = data[0];
  209.     wdsPtr[1].ptr = (void *)&data[1];
  210.     wdsPtr[3].length = 0;
  211.     wdsPtr[3].ptr = nil;
  212.  
  213.     pBlock->csCode = TCPSend;
  214.     pBlock->ioCRefNum = gTcpDrvrRef;
  215.     pBlock->csParam.send.ulpTimeoutValue = 0;
  216.     pBlock->csParam.send.ulpTimeoutAction = 1;
  217.     pBlock->csParam.send.validityFlags = 0xc0;
  218.     pBlock->csParam.send.pushFlag = false;
  219.     pBlock->csParam.send.urgentFlag = false;
  220.     pBlock->csParam.send.wdsPtr = (Ptr)wdsPtr;
  221.     err = PBControl(pBlock,false);
  222.     if (err!=noErr)
  223.         DoError(err);
  224.  
  225.     pBlock->csCode = TCPClose;
  226.     pBlock->ioCRefNum = gTcpDrvrRef;
  227.     pBlock->csParam.close.validityFlags = 0xC0;
  228.     pBlock->csParam.close.ulpTimeoutValue = 20;
  229.     pBlock->csParam.close.ulpTimeoutAction = 1;
  230.     err = PBControl(pBlock,false);
  231.     if (err!=noErr)
  232.         DoError(err);
  233.     
  234.     pBlock->csCode = TCPRelease;
  235.     pBlock->ioCRefNum = gTcpDrvrRef;
  236.     err = PBControl(pBlock,false);
  237.     if (err!=noErr)
  238.         DoError(err);
  239. }
  240.